package com.gcssloop.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import com.gcssloop.bubble_seekbar.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;

/**
 * 作用: 调节亮度 SeekBar
 * 作者: GcsSloop
 * 摘要: 调节亮度专用 SeekBar, 非通用.
 */
@SuppressWarnings("FieldCanBeLocal")
public class BubbleSeekBar extends View {
    // 静态数值
    private static final String KEY_PROGRESS_PRESENT = "PROGRESS";
    private static final String DEFAULT_FORMAT = "进度 %d%%";
    private static final int DEFAULT_MIN_VALUE = 0;         // 默认最小值
    private static final int DEFAULT_MAX_VALUE = 100;       // 默认最大值
    private static final int DEFAULT_SHADOW_RADIUS = 0;     // 阴影半径
    // 气泡
    private static final int DEFAULT_BUBBLE_COLOR = 0x88FFFFFF; // 气泡颜色
    private static final boolean DEFAULT_SHOW_BUBBLE = true;    // 默认显示气泡
    // 拖动按钮
    private static final int DEFAULT_THUMB_COLOR = 0xFFFFFFFF;              // 拖动按钮颜色
    private static final float DEFAULT_THUMB_WIDTH_RATIO = 3f / 70f;        // 拖动按钮粗细
    private static final float DEFAULT_THUMB_LENGTH_RATIO = 20f / 70f;      // 拖动按钮长短
    // 边框
    private static final int DEFAULT_BORDER_WIDTH = -1;                     // 边框宽度 (注意为此处，-1 表示使用比例)
    private static final int DEFAULT_BORDER_COLOR = 0xFFFFFFFF;             // 边框颜色
    private static final float DEFAULT_BORDER_WIDTH_RATIO = 2f / 70f;       // 边框
    // 文本
    private static final int DEFAULT_TEXT_COLOR_NORMAL = 0xAA000000;        // 默认文本颜色
    private static final int DEFAULT_TEXT_COLOR_POP = 0xAA000000;           // 弹出文本颜色
    // 背景
    private static final int DEFAULT_BACKGROUND_COLOR = 0xFFFFFFFF;         // 背景颜色
    // 内容
    private static final boolean DEFAULT_SHOW_CONTENT_RADIUS = false;       // 内容是否显示圆角

    // 基础比例
    private final float mBaseRatio = 70f / 170f;            // 基本宽高比
    private final float mRoundCornerRatio = 6f / 70f;       // 圆角
    private final float mThumbMarginRatio = 5f / 70f;       // 拖动按钮距离底部的固定距离
    private final float mEndLengthRatio = 10f / 70f;        // 底部不可拖动的距离
    private final float mTextSizeRatio = 8f / 70f;          // 文本大小
    // 气泡
    private final float mBubbleMaxRadiusRatio = 7f / 70f;   // 气泡最大半径
    private final float mBubbleMinRadiusRatio = 1f / 70f;   // 气泡最小半径

    // 可调节比例
    private int mThumbColor;                                // 拖动按钮颜色
    private float mThumbWidthRatio = 3f / 70f;              // 拖动按钮粗细
    private float mThumbLengthRatio = 20f / 70f;            // 拖动按钮长短
    private int mBorderColor;                               // 边框颜色
    private int mBackgroundColor;                           // 背景颜色
    private float mBorderWidthRatio = 2f / 70f;             // 边框宽度
    private int mTextColorNormal;                           // 文档普通颜色
    private int mTextColorPop;                              // 文本弹出颜色(即在拖动按钮靠近底部时文本弹出颜色)

    private float mShadowRadius;                            // 阴影半径
    private float mRoundCornerRadius;                       // 圆角半径
    private float mThumbMargin;                             // 拖动按钮 margin 距离底部的固定距离
    private float mThumbLength;                             // 拖动按钮长度
    private float mEndLength;                               // 拖动到底部是不可拖动的长度,一般为 mThumbMargin 的 2 倍
    private float mBorderWidth;                             // 边框宽度
    private RectF mContentRectF;                            // 内容区域
    private String mFormat;                                 // 文本显示的 Format
    private int mMinValue;                                  // 进度最小值
    private int mMaxValue;                                  // 进度最大值
    private int[] mShaderColors;                            // 渐变色

    private boolean mShowBubble;                            // 是否显示气泡
    private boolean mContentShowRadius;                     // 内容是否显示半径

    private Paint mPaint;                                   // 普通画笔,用于绘制背景和边框
    private Paint mClipPaint;                               // 剪裁画笔,用于剪裁内容区域
    private Paint mThumbPaint;                              // 拖动按钮画笔,用于绘制拖动按钮
    private Paint mShaderPaint;                             // 渲染器画笔,用于绘制进度渐变效果
    private Paint mTextPaint;                               // 文本画笔,用于绘制文本

    private Path mClipPath;                                 // ClipPath, 剪裁用
    private RectF mProgressRectF;                           // 进度区域
    private float mProgressPresent = 0.0f;                  // 当前进度 0.0 - 1.0
    private GestureDetector mDetector;


    public BubbleSeekBar(Context context) {
        this(context, null);
    }

    public BubbleSeekBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }


    public BubbleSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setSaveEnabled(true);
        setLayerType(LAYER_TYPE_SOFTWARE, null);

        initAttrs(context, attrs);
        initData();
        initPaint();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BubbleSeekBar);
        mMinValue = ta.getInt(R.styleable.BubbleSeekBar_bub_min, DEFAULT_MIN_VALUE);
        mMaxValue = ta.getInt(R.styleable.BubbleSeekBar_bub_max, DEFAULT_MAX_VALUE);
        int progress = ta.getInt(R.styleable.BubbleSeekBar_bub_progress, 0);
        setProgress(progress);
        initFormat(ta);
        initBubble(ta);
        mShaderColors = getShaderColors(context, ta);
        mShadowRadius = ta.getDimensionPixelSize(R.styleable.BubbleSeekBar_bub_shadow_radius, dp2px(DEFAULT_SHADOW_RADIUS));
        // v1.3.0+
        mTextColorNormal = ta.getColor(R.styleable.BubbleSeekBar_bub_text_color_normal, DEFAULT_TEXT_COLOR_NORMAL);
        mTextColorPop = ta.getColor(R.styleable.BubbleSeekBar_bub_text_color_pop, DEFAULT_TEXT_COLOR_POP);
        mThumbColor = ta.getColor(R.styleable.BubbleSeekBar_bub_thumb_color, DEFAULT_THUMB_COLOR);
        mThumbWidthRatio = ta.getFloat(R.styleable.BubbleSeekBar_bub_thumb_width_ratio, DEFAULT_THUMB_WIDTH_RATIO);
        mThumbLengthRatio = ta.getFloat(R.styleable.BubbleSeekBar_bub_thumb_length_ratio, DEFAULT_THUMB_LENGTH_RATIO);
        mBorderColor = ta.getColor(R.styleable.BubbleSeekBar_bub_border_color, DEFAULT_BORDER_COLOR);
        mBorderWidthRatio = ta.getFloat(R.styleable.BubbleSeekBar_bub_border_width_ratio, DEFAULT_BORDER_WIDTH_RATIO);
        mBorderWidth = ta.getDimensionPixelSize(R.styleable.BubbleSeekBar_bub_border_width, DEFAULT_BORDER_WIDTH);
        mBackgroundColor = ta.getColor(R.styleable.BubbleSeekBar_bub_background_color, DEFAULT_BACKGROUND_COLOR);
        mContentShowRadius = ta.getBoolean(R.styleable.BubbleSeekBar_bub_content_show_radius, DEFAULT_SHOW_CONTENT_RADIUS);
        ta.recycle();
    }

    private void initFormat(TypedArray ta) {
        String format = ta.getString(R.styleable.BubbleSeekBar_bub_format);
        if (null != format && format.contains("%d")) {
            mFormat = format;
        } else {
            mFormat = DEFAULT_FORMAT;
        }
    }

    // 获取 Arc 颜色数组
    private int[] getShaderColors(Context context, TypedArray ta) {
        int[] ret;
        int resId = ta.getResourceId(R.styleable.BubbleSeekBar_bub_colors, 0);
        if (0 == resId) {
            resId = R.array.bubble_colors_default;
        }
        TypedArray colorArray = context.getResources().obtainTypedArray(resId);
        ret = new int[colorArray.length()];
        for (int i = 0; i < colorArray.length(); i++) {
            ret[i] = colorArray.getColor(i, 0);
        }
        colorArray.recycle();
        return ret;
    }

    private void initData() {
        mDetector = new GestureDetector(getContext(), new OnClickListener());
        mContentRectF = new RectF();
        mProgressRectF = new RectF();
        mClipPath = new Path();
    }

    private void initPaint() {
        mClipPaint = new Paint();
        mClipPaint.setAntiAlias(true);
        mClipPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mClipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        mPaint = new Paint();
        mPaint.setColor(Color.WHITE);
        mPaint.setAntiAlias(true);

        mThumbPaint = new Paint();
        mThumbPaint.setColor(mThumbColor);
        mThumbPaint.setAntiAlias(true);
        mThumbPaint.setStrokeCap(Paint.Cap.ROUND);

        mShaderPaint = new Paint();
        mShaderPaint.setAntiAlias(true);

        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(0xaa000000);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mTextBound = new Rect();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        float pl = getPaddingLeft() + mShadowRadius;
        float pt = getPaddingTop() + mShadowRadius;
        float pr = getPaddingRight() + mShadowRadius;
        float pb = getPaddingBottom() + mShadowRadius;
        float safeWidth = w - pl - pr;
        float safeHeight = h - pt - pb;
        float startX, startY, mContentWidth, mContentHeight;
        if (safeWidth / safeHeight >= mBaseRatio) {
            // 以高度为准
            mContentHeight = safeHeight;
            mContentWidth = mContentHeight * mBaseRatio;
            startX = pl + (safeWidth - mContentWidth) / 2;
            startY = pt;
        } else {
            mContentWidth = safeWidth;
            mContentHeight = mContentWidth / mBaseRatio;
            startX = pl;
            startY = pt + (safeHeight - mContentHeight) / 2;
        }

        if (mBorderWidth < 0) {
            mBorderWidth = mContentWidth * mBorderWidthRatio;
        }
        mRoundCornerRadius = mContentWidth * mRoundCornerRatio;
        mThumbMargin = mContentWidth * mThumbMarginRatio;
        float thumbWidth = mContentWidth * mThumbWidthRatio;
        mThumbLength = mContentWidth * mThumbLengthRatio;
        mEndLength = mContentWidth * mEndLengthRatio;
        float fix = mBorderWidth / 2;
        mContentRectF.set(startX + fix, startY + fix, startX + mContentWidth - mBorderWidth, startY + mContentHeight - mBorderWidth);

        mPaint.setStrokeWidth(mBorderWidth);
        mThumbPaint.setStrokeWidth(thumbWidth);

        mClipPath.addRoundRect(mContentRectF, mRoundCornerRadius, mRoundCornerRadius, Path.Direction.CW);
        mClipPath.moveTo(0, 0);
        mClipPath.moveTo(w, h);

        // 初始化渐变
        float distance = 1f / (mShaderColors.length - 1);
        float pos[] = new float[mShaderColors.length];
        for (int i = 0; i < mShaderColors.length; i++) {
            pos[i] = 0 + (distance * i);
        }
        LinearGradient lg = new LinearGradient(mContentRectF.centerX(), mContentRectF.top,
                mContentRectF.centerX(), mContentRectF.bottom, mShaderColors, pos, Shader.TileMode.CLAMP);
        mShaderPaint.setShader(lg);

        float textSize = mContentWidth * mTextSizeRatio;
        mTextPaint.setTextSize(textSize);

        onSizeChangesBubble();
    }

    private boolean moved = false;          // 是否移动过
    private boolean canDrag = false;        // 是否允许拖动
    private int lastProgress = -1;          // 上一次的进度

    @Override
    @SuppressLint("ClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        float y = event.getY();
        switch (action) {
            case ACTION_DOWN:
                moved = false;
                canDrag = y >= mProgressTop - mThumbMargin * 3 && y <= mProgressTop + mThumbMargin * 3;
                if (null != mOnProgressChangeListener) {
                    mOnProgressChangeListener.onStartTrackingTouch(this);
                }
                break;
            case ACTION_MOVE:
                if (!canDrag) break;
                mProgressPresent = 1f - ((y - mThumbMargin - mContentRectF.top) / (mContentRectF.height() - mEndLength));
                if (mProgressPresent < 0) {
                    mProgressPresent = 0;
                }
                if (mProgressPresent > 1.0f) {
                    mProgressPresent = 1.0f;
                }
                if (null != mOnProgressChangeListener && getProgress() != lastProgress) {
                    mOnProgressChangeListener.onProgressChanged(this, getProgress(), true);
                    lastProgress = getProgress();
                }
                moved = true;
                break;
            case ACTION_UP:
            case ACTION_CANCEL:
                if (null != mOnProgressChangeListener && moved) {
                    mOnProgressChangeListener.onStopTrackingTouch(this);
                }
                break;
        }
        mDetector.onTouchEvent(event);
        invalidate();
        return true;
    }

    private class OnClickListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            float y = e.getY();
            // 判断是否点击在了内容区域
            if (!mContentRectF.contains(e.getX(), e.getY())) return false;
            mProgressPresent = 1f - ((y - mThumbMargin - mContentRectF.top) / (mContentRectF.height() - mEndLength));
            if (mProgressPresent < 0) {
                mProgressPresent = 0;
            }
            if (mProgressPresent > 1.0f) {
                mProgressPresent = 1.0f;
            }
            // 事件回调
            if (null != mOnProgressChangeListener) {
                mOnProgressChangeListener.onProgressChanged(BubbleSeekBar.this, getProgress(), true);
                mOnProgressChangeListener.onStopTrackingTouch(BubbleSeekBar.this);
            }
            return true;
        }
    }


    private float mProgressTop;     // 当前 Progress 的顶部
    private float thumbStartX;      // 拖动按钮开始位置 x
    private float thumbStopX;       // 拖动按钮结束位置 x
    private float thumbY;           // 拖动按钮在 y 轴位置
    private String text;            // 显示的文本
    private float textStartX;       // 文本开始位置 x
    private float textStartY;       // 文本开始位置 y
    private Rect mTextBound;        // 文本所占区域

    private void updateInfo() {
        mProgressTop = mContentRectF.bottom - mEndLength - (mContentRectF.height() - mEndLength) * (mProgressPresent);
        mProgressRectF.set(mContentRectF.left, mProgressTop, mContentRectF.right, mContentRectF.bottom);
        thumbStartX = mProgressRectF.left + (mProgressRectF.width() - mThumbLength) / 2;
        thumbStopX = thumbStartX + mThumbLength;
        thumbY = mProgressRectF.top + mThumbMargin;
        text = String.format(mFormat, getProgress());
        mTextPaint.getTextBounds(text, 0, text.length(), mTextBound);

        textStartX = mContentRectF.centerX();
        if (mProgressPresent >= 0.1) {
            mTextPaint.setColor(mTextColorNormal);
            textStartY = mProgressTop + 2 * mThumbMargin + mTextBound.height();
        } else {
            mTextPaint.setColor(mTextColorPop);
            textStartY = mProgressTop - mThumbMargin;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        updateInfo();

        canvas.save();
        // 绘制背景
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setShadowLayer(mShadowRadius * 1.5f, 0, 0, getColor());
        mPaint.setColor(mBackgroundColor);
        canvas.drawRoundRect(mContentRectF, mRoundCornerRadius, mRoundCornerRadius, mPaint);
        mPaint.clearShadowLayer();

        // 内容剪裁
        canvas.clipPath(mClipPath);
        // 绘制表示进度的区域
        if (mContentShowRadius) {
            canvas.drawRoundRect(mProgressRectF, mRoundCornerRadius, mRoundCornerRadius, mShaderPaint);
        } else {
            canvas.drawRect(mProgressRectF, mShaderPaint);
        }
        // 绘制气泡
        drawBubble(canvas);
        // 绘制拖动按钮
        canvas.drawLine(thumbStartX, thumbY, thumbStopX, thumbY, mThumbPaint);
        // 绘制文本
        canvas.drawText(text, textStartX, textStartY, mTextPaint);

        canvas.restore();

        // 绘制边框
        if (mBorderWidth > 0) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(mBorderColor);
            canvas.drawRoundRect(mContentRectF, mRoundCornerRadius, mRoundCornerRadius, mPaint);
        }
    }

    //--- 状态存储 ---------------------------------------------------------------------------------

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable("superState", super.onSaveInstanceState());
        bundle.putFloat(KEY_PROGRESS_PRESENT, mProgressPresent);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            this.mProgressPresent = bundle.getFloat(KEY_PROGRESS_PRESENT);
            state = bundle.getParcelable("superState");
        }
        super.onRestoreInstanceState(state);
    }

    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
    }

    //--- 气泡效果 ---------------------------------------------------------------------------------

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        startBubbleSync();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopBubbleSync();
    }

    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (visibility == VISIBLE) {
            startBubbleSync();
        } else {
            stopBubbleSync();
        }
    }

    private int mBubbleMaxRadius = 30;          // 气泡最大半径
    private int mBubbleMinRadius = 5;           // 气泡最小半径

    private int mBubbleMaxSize = 30;            // 气泡数量
    private int mBubbleRefreshTime = 20;        // 刷新频率
    private Paint mBubblePaint;                 // 气泡画笔

    private class Bubble {
        int radius;     // 气泡半径
        float speedY;   // 上升速度
        float speedX;   // 平移速度
        float x;        // 气泡x坐标
        float y;        // 气泡y坐标
    }

    private List<Bubble> mBubbles = new ArrayList<>();

    private Random random = new Random();
    private Thread mBubbleThread;

    // 初始化气泡
    private void initBubble(TypedArray ta) {
        int color = ta.getColor(R.styleable.BubbleSeekBar_bub_bubble_color, DEFAULT_BUBBLE_COLOR);
        mShowBubble = ta.getBoolean(R.styleable.BubbleSeekBar_bub_show_bubble, DEFAULT_SHOW_BUBBLE);
        mBubblePaint = new Paint();
        mBubblePaint.setColor(color);
    }

    // 控件大小变化
    private void onSizeChangesBubble() {
        mBubbleMaxRadius = (int) (mContentRectF.width() * mBubbleMaxRadiusRatio);
        mBubbleMinRadius = (int) (mContentRectF.width() * mBubbleMinRadiusRatio);
    }

    // 开始气泡线程
    private void startBubbleSync() {
        stopBubbleSync();
        if (!mShowBubble) return;
        mBubbleThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(mBubbleRefreshTime);
                        tryCreateBubble();
                        refreshBubbles();
                        postInvalidate();
                    } catch (InterruptedException e) {
                        System.out.println("Bubble线程结束");
                        break;
                    }
                }
            }
        };
        mBubbleThread.start();
    }

    // 停止气泡线程
    private void stopBubbleSync() {
        if (null == mBubbleThread) return;
        mBubbleThread.interrupt();
        mBubbleThread = null;
    }

    // 绘制气泡
    private void drawBubble(Canvas canvas) {
        List<Bubble> list = new ArrayList<>(mBubbles);
        for (Bubble bubble : list) {
            if (null == bubble) continue;
            canvas.drawCircle(bubble.x, bubble.y,
                    bubble.radius, mBubblePaint);
        }
    }

    // 尝试创建气泡
    private void tryCreateBubble() {
        if (mBubbles.size() >= mBubbleMaxSize) {
            return;
        }
        if (random.nextFloat() < 0.95) {
            return;
        }
        Bubble bubble = new Bubble();
        int radius = random.nextInt(mBubbleMaxRadius - mBubbleMinRadius);
        radius += mBubbleMinRadius;
        float speedY = random.nextFloat() * 5;
        while (speedY < 1) {
            speedY = random.nextFloat() * 5;
        }
        bubble.radius = radius;
        bubble.speedY = speedY;
        bubble.x = mContentRectF.centerX();
        bubble.y = mContentRectF.bottom - radius;
        float speedX = random.nextFloat() - 0.5f;
        while (speedX == 0) {
            speedX = random.nextFloat() - 0.5f;
        }
        bubble.speedX = speedX * 2;
        mBubbles.add(bubble);
    }

    // 刷新气泡位置，对于超出区域的气泡进行移除
    private void refreshBubbles() {
        List<Bubble> list = new ArrayList<>(mBubbles);
        for (Bubble bubble : list) {
            if (bubble.y - bubble.speedY <= mContentRectF.top) {
                mBubbles.remove(bubble);
            } else {
                int i = mBubbles.indexOf(bubble);
                if (bubble.x + bubble.speedX <= mContentRectF.left + mBorderWidth / 2 + bubble.radius) {
                    bubble.x = mContentRectF.left + mBorderWidth / 2 + bubble.radius;
                } else if (bubble.x + bubble.speedX >= mContentRectF.right - mBorderWidth / 2 - bubble.radius) {
                    bubble.x = mContentRectF.right - mBorderWidth / 2 - bubble.radius;
                } else {
                    bubble.x = bubble.x + bubble.speedX;
                }
                bubble.y = bubble.y - bubble.speedY;
                mBubbles.set(i, bubble);
            }
        }
    }

    //--- 线性取色 ---------------------------------------------------------------------------------

    /**
     * 获取当前进度的具体颜色
     *
     * @return 当前进度在渐变中的颜色
     */
    public int getColor() {
        return getColor((1 - mProgressPresent));
    }

    /**
     * 获取某个百分比位置的颜色
     *
     * @param radio 取值[0,1]
     * @return 最终颜色
     */
    private int getColor(float radio) {
        float diatance = 1.0f / (mShaderColors.length - 1);
        int startColor;
        int endColor;
        if (radio >= 1) {
            return mShaderColors[mShaderColors.length - 1];
        }
        for (int i = 0; i < mShaderColors.length; i++) {
            if (radio <= i * diatance) {
                if (i == 0) {
                    return mShaderColors[0];
                }
                startColor = mShaderColors[i - 1];
                endColor = mShaderColors[i];
                float areaRadio = getAreaRadio(radio, diatance * (i - 1), diatance * i);
                return getColorFrom(startColor, endColor, areaRadio);
            }
        }
        return -1;
    }

    /**
     * 计算当前比例在子区间的比例
     *
     * @param radio         总比例
     * @param startPosition 子区间开始位置
     * @param endPosition   子区间结束位置
     * @return 自区间比例[0, 1]
     */
    private float getAreaRadio(float radio, float startPosition, float endPosition) {
        return (radio - startPosition) / (endPosition - startPosition);
    }

    /**
     * 取两个颜色间的渐变区间 中的某一点的颜色
     *
     * @param startColor 开始的颜色
     * @param endColor   结束的颜色
     * @param radio      比例 [0, 1]
     * @return 选中点的颜色
     */
    private int getColorFrom(int startColor, int endColor, float radio) {
        int redStart = Color.red(startColor);
        int blueStart = Color.blue(startColor);
        int greenStart = Color.green(startColor);
        int redEnd = Color.red(endColor);
        int blueEnd = Color.blue(endColor);
        int greenEnd = Color.green(endColor);

        int red = (int) (redStart + ((redEnd - redStart) * radio + 0.5));
        int greed = (int) (greenStart + ((greenEnd - greenStart) * radio + 0.5));
        int blue = (int) (blueStart + ((blueEnd - blueStart) * radio + 0.5));
        return Color.argb(255, red, greed, blue);
    }

    //--- 公开方法 ---------------------------------------------------------------------------------

    public int getProgress() {
        return (int) (mProgressPresent * (mMaxValue - mMinValue) + mMinValue);
    }

    public void setProgress(int progress) {
        if (progress < 0) progress = 0;
        if (progress > mMaxValue) progress = mMaxValue;
        mProgressPresent = (progress - mMinValue) * 1.0f / (mMaxValue - mMinValue);
        if (null != mOnProgressChangeListener) {
            mOnProgressChangeListener.onProgressChanged(this, getProgress(), false);
        }
        invalidate();
    }


    OnProgressChangeListener mOnProgressChangeListener;

    public void setOnProgressChangeListener(OnProgressChangeListener onProgressChangeListener) {
        mOnProgressChangeListener = onProgressChangeListener;
    }

    public interface OnProgressChangeListener {
        /**
         * 进度发生变化
         *
         * @param seekBar  拖动按钮
         * @param progress 当前进度数值
         * @param isUser   是否是用户操作, true 表示用户拖动, false 表示通过代码设置
         */
        void onProgressChanged(BubbleSeekBar seekBar, int progress, boolean isUser);

        /**
         * 用户开始拖动
         *
         * @param seekBar SeekBar
         */
        void onStartTrackingTouch(BubbleSeekBar seekBar);

        /**
         * 用户结束拖动
         *
         * @param seekBar SeekBar
         */
        void onStopTrackingTouch(BubbleSeekBar seekBar);
    }
}
